package gatperdut.chato.core.interpreter.login;

import gatperdut.chato.constants.CSConstantsCommandResult.CheckLoginResult;
import gatperdut.chato.constants.CSConstantsCommandResult.CommandExecutionResult;
import gatperdut.chato.constants.CSConstantsPlayerState.PlayerState;
import gatperdut.chato.core.ChatoServer;
import gatperdut.chato.core.entities.PlayerController;
import gatperdut.chato.core.interpreter.PlayerInterpreter;
import gatperdut.chato.model.Chato.Player.Player;

import org.apache.log4j.Logger;

public class PlayerLogin {

    private final Logger logger = Logger.getLogger( PlayerLogin.class );

    private final PlayerInterpreter interpreter;

    private String providedUsername;

    private String providedPassword;

    private int numberAttempts = 0;

    public PlayerLogin( PlayerInterpreter interpreter ) {
        this.interpreter = interpreter;
    }

    // --compare provided login data against db
    private CheckLoginResult checkLogin() {
        logger.debug( "Attempted login with " + providedUsername + " / " + providedPassword );

        if ( getChatoServer().getEntityHandler().playerExists( providedUsername, providedPassword ) ) {
            // --there -is- a match...is the client already logged in?
            if ( getChatoServer().getEntityHandler().isPlayerLoggedIn( providedUsername ) ) {
                return CheckLoginResult.ALREADY_LOGGED;
            }
            // --if it was not logged, now it is!
            return CheckLoginResult.MATCHING;
        }
        else {
            return CheckLoginResult.NON_MATCHING;
        }
    }

    // --handle providing username
    private CommandExecutionResult handleProvidingUsername( String command ) {
        if ( !getChatoServer().getEntityHandler().isUsernameRegistered( command ) ) {
            getController().tx( "That username is not registered. Please try again." );
            return CommandExecutionResult.OK;
        }
        providedUsername = command;
        getController().tx( "Your password?" );
        getController().setPlayerState( PlayerState.LOGIN_PROVIDING_PASSWORD );
        return CommandExecutionResult.OK;
    }

    // --handle providing password
    private CommandExecutionResult handleProvidingPassword( String command ) {
        providedPassword = command;
        CheckLoginResult loginResult = checkLogin();
        if ( loginResult == CheckLoginResult.MATCHING ) {
            // --TODO handle main menu
            getChatoServer().getEntityHandler().logInPlayer( getChatoServer().getEntityHandler().retrievePlayer( providedUsername ) );
            return CommandExecutionResult.LOGIN_PASSWORD_MATCHING;
        }
        else if ( loginResult == CheckLoginResult.NON_MATCHING ) {
            getController().tx( "Username or password non-matching." );
            numberAttempts++;
            if ( numberAttempts == 3 ) {
                getController().tx( "You have failed to log-in 3 times. Closing connection ..." );
                logger.info( getController().whoAmI() + " failed to log-in for 3 times." );
                return CommandExecutionResult.QUIT_LOGIN_MAX_ATTEMPTS;
            }
            else {
                getController().tx( "Try again ... your username?" );
                getController().setPlayerState( PlayerState.LOGIN_PROVIDING_USERNAME );
                return CommandExecutionResult.LOGIN_PASSWORD_NON_MATCHING;
            }
        }
        else if ( loginResult == CheckLoginResult.ALREADY_LOGGED ) {
            getController().tx( "The account " + providedUsername + " is already logged in! This has been reported. Closing connection ..." );
            logger.info( "Detected duplicate log-in for username " + providedUsername + " from " + getController().whoAmI() + "." );
            return CommandExecutionResult.QUIT_LOGIN_ALREADY_LOGGED;
        }
        else {
            logger.error( "checkLogin() returned an unknown state." );
            return CommandExecutionResult.QUIT_INSANITY;
        }
    }

    // --handle loginModel
    public CommandExecutionResult handleLogin( String command ) {
        switch ( getController().getPlayerState() ) {
        case LOGIN_PROVIDING_USERNAME:
            return handleProvidingUsername( command );
        case LOGIN_PROVIDING_PASSWORD:
            CommandExecutionResult providingPasswordResult = handleProvidingPassword( command );
            if ( providingPasswordResult == CommandExecutionResult.LOGIN_PASSWORD_MATCHING ) {
                // --alles OK
                Player player = getChatoServer().getEntityHandler().retrievePlayer( providedUsername );
                getController().setPlayer( player );
                getController().tx( "Hello, " + providedUsername + "." );
                logger.info( getController().whoAmI() + " has logged in." );
            }
            return providingPasswordResult;
        default:
            logger.error( "Undefined login state for " + getController().whoAmI() + "." );
            return CommandExecutionResult.QUIT_INSANITY;
        }
    }

    public PlayerController getController() {
        return getInterpreter().getController();
    }

    public ChatoServer getChatoServer() {
        return getInterpreter().getController().getChatoServer();
    }

    public PlayerInterpreter getInterpreter() {
        return interpreter;
    }

}
